#pragma once
#include "util.hpp"
#include <iostream>
#include <memory>
#include <fstream>
#include <assert.h>
#include <sstream>

namespace log
{
    class Sink
    {
    public:
        using ptr = std::shared_ptr<Sink>;
        Sink(){}
        virtual ~Sink() {}
        virtual void logOut(const char *data, int len) = 0;
    };

    // 输出到->标准输出
    class StdOutSink : public Sink
    {
    private:
        void logOut(const char *data, int len)
        {
            std::cout.write(data, len);
        }
    };

    // 输出到->文件
    class FileSink : public Sink
    {
    public:
        FileSink(const std::string &filename) : _filename(filename)
        {
            File::createDir(File::getPath(filename));              // 创建文件
            _ofs.open(filename, std::ios::binary | std::ios::app); // 以二进制追加的方式打开文件
            assert(_ofs.is_open());                                // 判断是否打开成功
        }
        void logOut(const char *data, int len)
        {
            _ofs.write(data, len); // 写入文件
            assert(_ofs.good());
        }

    private:
        std::string _filename;
        std::ofstream _ofs;
    };

    // 输出到->滚动文件（当某个文件存储大小满_maxsize时,切换另一个文件进行存储）
    class RollSink : public Sink
    {
    public:
        RollSink(const std::string &basename, int maxsize)
            : _basename(basename), _maxsize(maxsize), _cursize(0), _namecount(0)
        {
            std::string filename = createFileName();
            File::createDir(File::getPath(filename));
            _ofs.open(filename, std::ios::binary | std::ios::app);
            assert(_ofs.is_open());
        }
        void logOut(const char *data, int len)
        {
            if (_cursize >= _maxsize)
            {
                _ofs.close(); // 关闭当前打开的文件
                std::string filename = createFileName();
                File::createDir(File::getPath(filename));
                _ofs.open(filename, std::ios::binary | std::ios::app);
                assert(_ofs.is_open());
                _cursize = 0;
            }
            _ofs.write(data, len);
            assert(_ofs.good());
            _cursize += len; //当前存储大小进行累加
        }

    private:
        // 文件名为: _basename + 年月日时分秒
        std::string createFileName()
        {
            std::stringstream ss;
            ss << _basename;
            struct tm t;
            time_t tt = Date::curTime();
            localtime_r(&tt, &t);
            ss << t.tm_year + 1900 << t.tm_mon + 1 << t.tm_mday << t.tm_hour << t.tm_min << t.tm_sec << "-" << _namecount++ << ".log";
            return ss.str();
        }

    private:
        std::string _basename;
        std::ofstream _ofs;
        int _maxsize;
        int _cursize;
        int _namecount; //文件名计数 
    };

    class SinkFactory
    {
    public:
        template<typename SinkType, typename ...Args>
        static Sink::ptr create(Args&& ...args)
        {
            return std::make_shared<SinkType>(std::forward<Args>(args)...);
        }
    };
};